package cn.zwk.drawing.infrastructure.rendering;

import cn.zwk.drawing.domain.rendering.model.RenderResult;
import cn.zwk.drawing.domain.rendering.model.NodeGeometry;
import cn.zwk.drawing.domain.rendering.service.RenderingDomainService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.beans.factory.annotation.Value;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * PlantUML渲染服务实现
 */
@Slf4j
@Service
public class PlantUMLRenderingService implements RenderingDomainService {
    
    private final HttpClient httpClient;
    private final Map<String, RenderResult> asyncResults = new ConcurrentHashMap<>();
    
    @Value("${plantuml.server.url:https://www.plantuml.com/plantuml}")
    private String plantUmlServerUrl;
    
    @Value("${plantuml.render.timeout:30}")
    private int renderTimeout;
    
    public PlantUMLRenderingService() {
        this.httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();
    }
    
    @Override
    @Cacheable(value = "renderCache", key = "#plantUmlContent.hashCode()")
    public RenderResult renderToSvg(String plantUmlContent) {
        long startTime = System.currentTimeMillis();
        String renderId = UUID.randomUUID().toString();
        
        try {
            log.debug("开始渲染PlantUML: {}", renderId);
            
            // 验证语法
            if (!validatePlantUMLSyntax(plantUmlContent)) {
                return RenderResult.builder()
                        .renderId(renderId)
                        .status(RenderResult.RenderStatus.INVALID_SYNTAX)
                        .errorMessage("PlantUML语法错误")
                        .renderTime(System.currentTimeMillis() - startTime)
                        .renderedAt(LocalDateTime.now())
                        .build();
            }
            
            // 编码PlantUML内容
            String encoded = encodePlantUML(plantUmlContent);
            String svgUrl = plantUmlServerUrl + "/svg/" + encoded;
            
            // 发送HTTP请求
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(svgUrl))
                    .timeout(Duration.ofSeconds(renderTimeout))
                    .GET()
                    .build();
            
            HttpResponse<String> response = httpClient.send(request, 
                    HttpResponse.BodyHandlers.ofString());
            
            if (response.statusCode() == 200) {
                String svgContent = response.body();
                List<NodeGeometry> geometries = extractNodeGeometries(svgContent);
                
                RenderResult result = RenderResult.builder()
                        .renderId(renderId)
                        .sourceHash(generateContentHash(plantUmlContent))
                        .svgContent(svgContent)
                        .status(RenderResult.RenderStatus.SUCCESS)
                        .renderTime(System.currentTimeMillis() - startTime)
                        .nodeGeometries(geometries)
                        .renderedAt(LocalDateTime.now())
                        .build();
                
                log.info("PlantUML渲染成功: {} ({}ms)", renderId, result.getRenderTime());
                return result;
            } else {
                throw new RuntimeException("渲染服务返回错误: " + response.statusCode());
            }
            
        } catch (Exception e) {
            log.error("PlantUML渲染失败: {}", renderId, e);
            return RenderResult.builder()
                    .renderId(renderId)
                    .status(RenderResult.RenderStatus.FAILED)
                    .errorMessage(e.getMessage())
                    .renderTime(System.currentTimeMillis() - startTime)
                    .renderedAt(LocalDateTime.now())
                    .build();
        }
    }
    
    @Override
    public String renderToSvgAsync(String plantUmlContent) {
        String renderId = UUID.randomUUID().toString();
        
        // 异步执行渲染
        CompletableFuture.runAsync(() -> {
            RenderResult result = renderToSvg(plantUmlContent);
            asyncResults.put(renderId, result);
            
            // 5分钟后清理结果
            CompletableFuture.delayedExecutor(5, TimeUnit.MINUTES)
                    .execute(() -> asyncResults.remove(renderId));
        });
        
        return renderId;
    }
    
    @Override
    public RenderResult getAsyncRenderResult(String renderId) {
        return asyncResults.get(renderId);
    }
    
    @Override
    public List<NodeGeometry> extractNodeGeometries(String svgContent) {
        List<NodeGeometry> geometries = new ArrayList<>();
        
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new ByteArrayInputStream(svgContent.getBytes()));
            
            // 查找所有可能的节点元素
            NodeList textElements = doc.getElementsByTagName("text");
            NodeList rectElements = doc.getElementsByTagName("rect");
            NodeList polygonElements = doc.getElementsByTagName("polygon");
            
            // 基于文本元素查找节点
            Map<String, Element> textMap = new HashMap<>();
            for (int i = 0; i < textElements.getLength(); i++) {
                Element textEl = (Element) textElements.item(i);
                String text = textEl.getTextContent().trim();
                if (!text.isEmpty() && isNodeText(text)) {
                    textMap.put(text, textEl);
                }
            }
            
            // 为每个文本找到对应的图形元素
            for (Map.Entry<String, Element> entry : textMap.entrySet()) {
                String nodeText = entry.getKey();
                Element textEl = entry.getValue();
                
                // 查找关联的图形元素
                Element graphicEl = findAssociatedGraphic(textEl, doc);
                if (graphicEl != null) {
                    NodeGeometry geometry = extractGeometryFromElements(nodeText, textEl, graphicEl);
                    if (geometry != null) {
                        geometries.add(geometry);
                    }
                }
            }
            
        } catch (Exception e) {
            log.error("提取节点几何信息失败", e);
        }
        
        return geometries;
    }
    
    @Override
    public boolean validatePlantUMLSyntax(String plantUmlContent) {
        if (plantUmlContent == null || plantUmlContent.trim().isEmpty()) {
            return false;
        }
        
        String content = plantUmlContent.trim();
        
        // 基本语法检查
        return content.contains("@startuml") && content.contains("@enduml");
    }
    
    @Override
    public String generateContentHash(String plantUmlContent) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(plantUmlContent.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            return String.valueOf(plantUmlContent.hashCode());
        }
    }
    
    @Override
    public void clearRenderCache() {
        // Spring Cache会自动处理
        log.info("清理渲染缓存");
    }
    
    @Override
    public RenderServiceStatus getServiceStatus() {
        try {
            // 发送健康检查请求
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(plantUmlServerUrl + "/svg/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000"))
                    .timeout(Duration.ofSeconds(5))
                    .GET()
                    .build();
            
            HttpResponse<String> response = httpClient.send(request, 
                    HttpResponse.BodyHandlers.ofString());
            
            return response.statusCode() == 200 ? 
                    RenderServiceStatus.HEALTHY : RenderServiceStatus.DEGRADED;
                    
        } catch (Exception e) {
            log.warn("PlantUML服务健康检查失败", e);
            return RenderServiceStatus.UNAVAILABLE;
        }
    }
    
    /**
     * 编码PlantUML内容（简化实现）
     */
    private String encodePlantUML(String plantUmlContent) {
        // 实际实现需要使用PlantUML的编码算法
        return Base64.getUrlEncoder().withoutPadding()
                .encodeToString(plantUmlContent.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * 判断是否为节点文本
     */
    private boolean isNodeText(String text) {
        // 过滤掉箭头、注释等非节点文本
        Pattern nodePattern = Pattern.compile("^[A-Za-z0-9\\s\\u4e00-\\u9fa5]+$");
        return nodePattern.matcher(text).matches() && text.length() > 1;
    }
    
    /**
     * 查找文本关联的图形元素
     */
    private Element findAssociatedGraphic(Element textEl, Document doc) {
        // 简化实现：查找相邻的图形元素
        Element parent = (Element) textEl.getParentNode();
        NodeList children = parent.getChildNodes();
        
        for (int i = 0; i < children.getLength(); i++) {
            if (children.item(i) instanceof Element) {
                Element child = (Element) children.item(i);
                if ("rect".equals(child.getTagName()) || 
                    "polygon".equals(child.getTagName()) ||
                    "ellipse".equals(child.getTagName())) {
                    return child;
                }
            }
        }
        
        return null;
    }
    
    /**
     * 从元素中提取几何信息
     */
    private NodeGeometry extractGeometryFromElements(String nodeText, Element textEl, Element graphicEl) {
        try {
            double x = Double.parseDouble(graphicEl.getAttribute("x"));
            double y = Double.parseDouble(graphicEl.getAttribute("y"));
            double width = Double.parseDouble(graphicEl.getAttribute("width"));
            double height = Double.parseDouble(graphicEl.getAttribute("height"));
            
            return NodeGeometry.builder()
                    .nodeId(generateNodeId(nodeText))
                    .nodeName(nodeText)
                    .x(x)
                    .y(y)
                    .width(width)
                    .height(height)
                    .centerX(x + width / 2)
                    .centerY(y + height / 2)
                    .cssSelector(generateCssSelector(graphicEl))
                    .build();
                    
        } catch (Exception e) {
            log.warn("提取几何信息失败: {}", nodeText, e);
            return null;
        }
    }
    
    /**
     * 生成节点ID
     */
    private String generateNodeId(String nodeText) {
        return nodeText.toLowerCase()
                .replaceAll("\\s+", "_")
                .replaceAll("[^a-z0-9_]", "");
    }
    
    /**
     * 生成CSS选择器
     */
    private String generateCssSelector(Element element) {
        StringBuilder selector = new StringBuilder(element.getTagName());
        
        if (element.hasAttribute("id")) {
            selector.append("#").append(element.getAttribute("id"));
        }
        
        if (element.hasAttribute("class")) {
            selector.append(".").append(element.getAttribute("class"));
        }
        
        return selector.toString();
    }
}